﻿using Dapper;
using MaiPlanServer.IRepository;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace MaiPlanServer.Repository
{
    public class BaseRepository : IBaseRepository
    {
        public BaseRepository(IBaseConnection baseConnection)
        {
            BaseConnection = baseConnection.GetConn();
        }

        public SqlConnection BaseConnection { get; }




        #region Async /Await 异步流

        public async Task<IEnumerable<T>> QueryAllAsync<T>(string Sql) where T : class
        {
            return await BaseConnection.QueryAsync<T>(Sql);
        }

        public async Task<T> QueryFirstOrDefaultAsync<T>(string Sql, object Param) where T : class
        {
            return await BaseConnection.QueryFirstOrDefaultAsync<T>(Sql, Param);
        }
        public async Task<T> QueryFirstOrDefaultAsync<T>(string Sql) where T : class
        {
            return await BaseConnection.QueryFirstOrDefaultAsync<T>(Sql);
        }

        public async Task<IEnumerable<T>> QueryAsync<T>(string Sql, object Param) where T : class
        {
            return await BaseConnection.QueryAsync<T>(Sql, Param);
        }

        public async Task<bool> InsertAsync(string Sql, object Param)
        {
            var result = await BaseConnection.ExecuteAsync(Sql, Param);
            return result > 0;
        }
        public async Task<bool> InsertAsync<T>(T model) where T : class
        {
            var type = model.GetType();

            var Field = string.Join(',', type.GetProperties().Select(p => p.Name));
            var Values = string.Join(',', type.GetProperties().Select(p => "@" + p.Name));
            string Sql = $"Insert into {type.Name}({Field}) values ({Values})";

            return await BaseConnection.ExecuteAsync(Sql, model) > 0;
        }

        public async Task<bool> InsertAsync<T>(IEnumerable<T> list) where T : class
        {
            var type = list.First().GetType();

            var Field = string.Join(',', type.GetProperties().Select(p => p.Name));
            var Values = string.Join(',', type.GetProperties().Select(p => "@" + p.Name));
            string Sql = $"Insert into {type.Name}({Field}) values ({Values})";

            return await BaseConnection.ExecuteAsync(Sql, list) > 0;
        }

        public async Task<bool> DeleteAsync<T>(T model) where T : class
        {
            string Sql = $"Delete {model.GetType().Name} where Id=@Id";

            return await BaseConnection.ExecuteAsync(Sql, model) > 0;
        }

        public async Task<bool> DeleteAsync<T>(IEnumerable<T> list) where T : class
        {
            string Sql = $"Delete {list.First().GetType().Name} where Id=@Id";

            return await BaseConnection.ExecuteAsync(Sql, list) > 0;
        }
        public async Task<bool> DeleteAsync(string Sql, object Param)
        {
            return await BaseConnection.ExecuteAsync(Sql, Param) > 0;
        }

        public async Task<int> GetRecoreCountAsync(string Sql, object Param)
        {
            var count = Convert.ToInt32(await BaseConnection.ExecuteScalarAsync(Sql, Param));
            return count;
        }

        public async Task<int> GetRecoreCountAsync(string Sql)
        {
            var count = Convert.ToInt32(await BaseConnection.ExecuteScalarAsync(Sql));
            return count;
        }


        public async Task<bool> UpdateAsync(string sql, object Param)
        {
            var result = await BaseConnection.ExecuteAsync(sql, Param);

            return result > 0;
        }
        public async Task<bool> UpdateTranAsync(string sql, object Param)
        {
            if (BaseConnection.State != ConnectionState.Open)
            {
                BaseConnection.Open();
            }
            using (IDbTransaction tran = BaseConnection.BeginTransaction())
            {
                try
                {
                    var result = await BaseConnection.ExecuteAsync(sql, Param,tran);
                    if (result > 0)
                    {
                        tran.Commit();
                    }
                    else
                    {
                        tran.Rollback();
                    }
                   return  result > 0;
                }
                catch (Exception ex)
                {
                    tran.Rollback();
                }
                return false;
            }
        }
        public async Task<bool> UpdateAsync<T>(T model) where T : class
        {
            var type = model.GetType();

            var Field = string.Join(',', type.GetProperties().Select(p => $"{p.Name}=@{p.Name}"));
            //剔除Id
            Field = Field.Replace("Id=@Id,", "");
            string sql = $"update {type.Name} set {Field}  where Id=@Id";

            var result = await BaseConnection.ExecuteAsync(sql, model);

            return result > 0;
        }
        public async Task<bool> UpdateAsync<TKey,T>(T model,TKey key) where T : class
        {
            var type = model.GetType();

            var Field = string.Join(',', type.GetProperties().Select(p => $"{p.Name}=@{p.Name}"));
            //剔除Id
            Field = Field.Replace($"{key}=@{key},", "");
            string sql = $"update {type.Name} set {Field}  where {key}=@{key}";

            var result = await BaseConnection.ExecuteAsync(sql, model);

            return result > 0;
        }

        public async Task<bool> UpdateTranAsync<T,T2>(T model, IEnumerable<T2> list) where T : class
        {
            if (BaseConnection.State != ConnectionState.Open)
            {
                BaseConnection.Open();
            }
            using (IDbTransaction tran = BaseConnection.BeginTransaction())
            {
                try
                {

                    //主表 Model
                    var type = model.GetType();
                    var modelName = type.Name;

                    var Field = string.Join(',', type.GetProperties().Select(p => $"{p.Name}=@{p.Name}"));
                    //剔除Id
                    Field = Field.Replace("Id=@Id,", "");
                    string Sql = $"update {type.Name} set {Field}  where Id=@Id";

                    //Update To Model 
                    //更新Model
                    await BaseConnection.ExecuteAsync(Sql, model, tran);



                    //清除该单据所有子项数据 在进行新增
                    string tabName = list.First().GetType().Name;
                    //此处拼接：假如SalesOrder 为主表 SalesOrderItem 从表 则 删除主表所关联从表中的数据，利用SalesOrderId 主表编号
                    string delSql = $"Delete {list.First().GetType().Name} where {modelName}Id=@{modelName}Id";
                    await BaseConnection.ExecuteAsync(delSql, list, tran);


                    //执行新增
                    var t_type = list.First().GetType();
                    var t_Field = string.Join(',', t_type.GetProperties().Select(p => p.Name));
                    var t_Values = string.Join(',', t_type.GetProperties().Select(p => "@" + p.Name));
                    string addSql = $"Insert into {t_type.Name}({t_Field}) values ({t_Values})";

                    await BaseConnection.ExecuteAsync(addSql, list, tran);




                    tran.Commit();
                    return true;
                }
                catch (Exception ex)
                {
                    //此处应当日志记录
                    tran.Rollback();
                    return false;
                }
            }
        }



        public async Task<bool> InsertTranAsync<T,T2>(T model, IEnumerable<T2> list) where T : class
        {
            if (BaseConnection.State != ConnectionState.Open)
            {
                BaseConnection.Open();
            }
            using (IDbTransaction tran = BaseConnection.BeginTransaction())
            {
                try
                {

                    // Model 1
                    var type = model.GetType();

                    var Field = string.Join(',', type.GetProperties().Select(p => p.Name));
                    var Values = string.Join(',', type.GetProperties().Select(p => "@" + p.Name));
                    string Sql = $"Insert into {type.Name}({Field}) values ({Values})";


                    //Insert To Model
                    await BaseConnection.ExecuteAsync(Sql, model, tran);




                    //List Children
                    var t_type = list.FirstOrDefault().GetType();

                    var t_Field = string.Join(',', t_type.GetProperties().Select(p => p.Name));
                    var t_Values = string.Join(',', t_type.GetProperties().Select(p => "@" + p.Name));
                    string TModelSql = $"Insert into {t_type.Name}({t_Field}) values ({t_Values})";


                    //Insert To Model
                    await BaseConnection.ExecuteAsync(TModelSql, list, tran);





                    tran.Commit();
                    return true;
                }
                catch (Exception ex)
                {
                    //此处应当日志记录
                    tran.Rollback();
                    return false;
                }
            }
        }


        #endregion
    }
}
